package com.opal.config.shiro;

import com.opal.system.entity.table.OpalRole;
import com.opal.system.entity.table.OpalUser;
import com.opal.system.service.OpalPermissionService;
import com.opal.system.service.OpalRoleService;
import com.opal.system.service.OpalUserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.List;
import java.util.Set;

public class UserRealm extends AuthorizingRealm {

	@Autowired
	@Lazy		//懒加载bean，不然事务失效
	private OpalUserService userService;
	@Autowired
	@Lazy
	private OpalRoleService opalRoleService;
	@Autowired
	@Lazy
	private OpalPermissionService opalPermissionService;

	public void setName(String name) {
		name="userRealm";
		super.setName(name);
	}

	// 授权
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		OpalUser user = (OpalUser) principals.getPrimaryPrincipal();
		//根据用户名id获取角色
		List<OpalRole> roles = opalRoleService.getByUserIdRoles(user);
		//授权对象
		SimpleAuthorizationInfo s = new SimpleAuthorizationInfo();

		//根据角色ID获取所有权限
		Set<String> permissions = opalPermissionService.getByRoleIdListPermissions(roles);
		//授予权限
		if (permissions !=null)
			s.setStringPermissions(permissions);
		//授予角色
		for (OpalRole role : roles) {
			s.addRole(role.getRoleCode());
		}
		return s;
	}

	// 认证
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		UsernamePasswordToken t = (UsernamePasswordToken) token;
		// 获取用户输入的用户名
		String username = t.getUsername();
		if (username == null) {
			return null;// 内部会返回异常UnknownAccountException
		}

		// 获取数据库帐号
		OpalUser user = userService.findById(username);
		if (user == null) {
			return null;// 内部会返回异常UnknownAccountException
		}
		String salt = user.getUserSalt(); // 获取数据库存储的盐
		// 认证成功：参数需要：1：返回实体类，2、数据库获取的密码(必须)，3，ByteSource参数：暂时不明白，只知道需要用户盐，
		ByteSource bytes = ByteSource.Util.bytes(salt);
		AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getUserPassword(), bytes, this.getName());

		return info;
	}

}
